package org.springblade.modules.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.AllArgsConstructor;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.mal.MalListDTO;
import org.springblade.modules.admin.dto.sugar.BiWxPlanListDTO;
import org.springblade.modules.admin.entity.ElevatorPrincipalDept;
import org.springblade.modules.admin.entity.ElevatorPrincipalUser;
import org.springblade.modules.admin.entity.MaintainPlanContentUser;
import org.springblade.modules.admin.entity.MaintainPlanRelation;
import org.springblade.modules.admin.enums.ElevatorMaintainStatusEnums;
import org.springblade.modules.admin.enums.MaintainPlanContentEnum;
import org.springblade.modules.admin.enums.TaskStatusEnum;
import org.springblade.modules.admin.enums.WorkOrderTypeEnum;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.vo.sugar.bi.BILarkRescueCountSourceVO;
import org.springblade.modules.admin.vo.ElevatorEffectedVO;
import org.springblade.modules.admin.vo.ElevatorSimpleInfoVO;
import org.springblade.modules.admin.vo.sugar.bi.BIScreenElevatorPlanPartsVO;
import org.springblade.modules.admin.vo.sugar.bi.BIScreenElevatorVO;
import org.springblade.modules.admin.vo.sugar.bi.BIScreenElevatorPlanVO;
import org.springframework.stereotype.Service;

import java.util.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@AllArgsConstructor
@Service
public class BIServiceImpl implements BIService {

	private final ElevatorService elevatorService;
	private final ElevatorPrincipalDeptService elevatorPrincipalDeptService;
	private final ElevatorPrincipalUserService elevatorPrincipalUserService;
	private final IMaintainPlanContentUserService planContentUserService;
	private final IMaintainPlanRelationService planRelationService;
	private final IMaintainPlanContentService planContentService;

	@Override
	public List<BIScreenElevatorVO> selectBuildingElevator(String startDate, String endDate) {
		List<BIScreenElevatorVO> resultList = elevatorService.selectBIScreenBuildingElevator(startDate,endDate);
		if(Func.isNotEmpty(resultList)){
			List<ElevatorPrincipalDept> elevatorPrincipalDepts = elevatorPrincipalDeptService.listAll();
			List<ElevatorPrincipalUser> elevatorPrincipalUsers = elevatorPrincipalUserService.listAll();
			resultList.forEach(e -> {
				e.setElevatorPrincipalDeptNames(elevatorPrincipalDepts.stream().filter(j -> j.getElevatorId().equals(e.getElevatorId())).map(ElevatorPrincipalDept::getDeptName).distinct().collect(Collectors.joining(",")));
				e.setElevatorPrincipalUserNames(elevatorPrincipalUsers.stream().filter(j -> j.getElevatorId().equals(e.getElevatorId())).map(ElevatorPrincipalUser::getRealName).distinct().collect(Collectors.joining(",")));
			});
		}
		return resultList;
	}

	@Override
	public List<BIScreenElevatorPlanVO> selectBuildingElevatorWx(String startDate, String endDate) {
		if(Func.isEmpty(startDate) || Func.isEmpty(endDate)){
			startDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.date(),-30));
			endDate = DateUtil.formatDate(DateUtil.date());
		}
		List<BIScreenElevatorPlanVO> resultList = elevatorService.selectBIScreenBuildingElevatorWx(startDate,endDate);
		if(Func.isNotEmpty(resultList)){
			List<Long> planIds = resultList.stream().map(BIScreenElevatorPlanVO::getPlanId).collect(Collectors.toList());
			List<MaintainPlanContentUser> planContentUsers = planContentUserService.listAllByPlanIds(planIds);
//			List<ElevatorPrincipalDept> elevatorPrincipalDepts = elevatorPrincipalDeptService.listAll();
//			List<ElevatorPrincipalUser> elevatorPrincipalUsers = elevatorPrincipalUserService.listAll();
			resultList.forEach(e -> {
//				e.setElevatorPrincipalDeptNames(elevatorPrincipalDepts.stream().filter(j -> j.getElevatorId().equals(e.getElevatorId())).map(ElevatorPrincipalDept::getDeptName).distinct().collect(Collectors.joining(",")));
//				e.setElevatorPrincipalUserNames(elevatorPrincipalUsers.stream().filter(j -> j.getElevatorId().equals(e.getElevatorId())).map(ElevatorPrincipalUser::getRealName).distinct().collect(Collectors.joining(",")));
				e.setPlanUsers(planContentUsers.stream().filter(j -> j.getPlanId().equals(e.getPlanId())).map(MaintainPlanContentUser::getUserName).distinct().collect(Collectors.joining(",")));
			});
		}
		return resultList;
	}

	@Override
	public List<BIScreenElevatorPlanPartsVO> selectBuildingElevatorWxWork(String startDate, String endDate, Integer planType) {
		if(Func.isEmpty(startDate) || Func.isEmpty(endDate)){
			startDate = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.date(),-30));
			endDate = DateUtil.formatDate(DateUtil.date());
		}
		List<BIScreenElevatorPlanPartsVO> resultList;
		if(MaintainPlanContentEnum.MAINTAIN_WX.getId() == planType){
			resultList = elevatorService.selectBuildingElevatorWxWork(startDate,endDate);
		}else {
			resultList = elevatorService.selectBuildingElevatorPartsWork(startDate,endDate);
		}
		if(Func.isNotEmpty(resultList)){
			List<Long> planIds = resultList.stream().map(BIScreenElevatorPlanVO::getPlanId).collect(Collectors.toList());
			Map<Long,List<MaintainPlanRelation>> planGroup = new HashMap<>();
			if(MaintainPlanContentEnum.MAINTAIN_PARTS.getId() == planType){
				List<MaintainPlanRelation> planRelations = planRelationService.selectPartsRelaWxPlanIds(planIds);
				if(Func.isNotEmpty(planRelations)){
					planGroup = planRelations.stream().collect(Collectors.groupingBy(MaintainPlanRelation::getOwnPlanId));
				}
			}
			List<MaintainPlanContentUser> planContentUsers = planContentUserService.listAllByPlanIds(planIds);
//			List<ElevatorPrincipalDept> elevatorPrincipalDepts = elevatorPrincipalDeptService.listAll();
//			List<ElevatorPrincipalUser> elevatorPrincipalUsers = elevatorPrincipalUserService.listAll();
			Map<Long, List<MaintainPlanRelation>> finalPlanGroup = planGroup;
			resultList.forEach(e -> {
//				e.setElevatorPrincipalDeptNames(elevatorPrincipalDepts.stream().filter(j -> j.getElevatorId().equals(e.getElevatorId())).map(ElevatorPrincipalDept::getDeptName).distinct().collect(Collectors.joining(",")));
//				e.setElevatorPrincipalUserNames(elevatorPrincipalUsers.stream().filter(j -> j.getElevatorId().equals(e.getElevatorId())).map(ElevatorPrincipalUser::getRealName).distinct().collect(Collectors.joining(",")));
				e.setPlanUsers(planContentUsers.stream().filter(j -> j.getPlanId().equals(e.getPlanId())).map(MaintainPlanContentUser::getUserName).distinct().collect(Collectors.joining(",")));
				if(Func.isNotEmpty(e.getPartsIds()) && Func.isNotEmpty(e.getPartsNames())){
					List<String> partsIds = Func.toStrList(e.getPartsIds());
					if(partsIds.size() == 1){
						e.setPartsIdA(partsIds.get(0));
					}
					if(partsIds.size() == 2){
						e.setPartsIdA(partsIds.get(0));
						e.setPartsIdB(partsIds.get(1));
					}
					if(partsIds.size() == 3){
						e.setPartsIdA(partsIds.get(0));
						e.setPartsIdB(partsIds.get(1));
						e.setPartsIdC(partsIds.get(2));
					}
					if(partsIds.size() == 4){
						e.setPartsIdA(partsIds.get(0));
						e.setPartsIdB(partsIds.get(1));
						e.setPartsIdC(partsIds.get(2));
						e.setPartsIdD(partsIds.get(3));
					}
					if(partsIds.size() >= 5){
						e.setPartsIdA(partsIds.get(0));
						e.setPartsIdB(partsIds.get(1));
						e.setPartsIdC(partsIds.get(2));
						e.setPartsIdD(partsIds.get(3));
						e.setPartsIdE(partsIds.get(4));
					}
					List<String> partsNames = Func.toStrList("&amp;&amp;",e.getPartsNames());
					if(partsIds.size() == 1){
						e.setPartsNameA(partsNames.get(0));
					}
					if(partsIds.size() == 2){
						e.setPartsNameA(partsNames.get(0));
						e.setPartsNameB(partsNames.get(1));
					}
					if(partsIds.size() == 3){
						e.setPartsNameA(partsNames.get(0));
						e.setPartsNameB(partsNames.get(1));
						e.setPartsNameC(partsNames.get(2));
					}
					if(partsIds.size() == 4){
						e.setPartsNameA(partsNames.get(0));
						e.setPartsNameB(partsNames.get(1));
						e.setPartsNameC(partsNames.get(2));
						e.setPartsNameD(partsNames.get(3));
					}
					if(partsIds.size() >= 5){
						e.setPartsNameA(partsNames.get(0));
						e.setPartsNameB(partsNames.get(1));
						e.setPartsNameC(partsNames.get(2));
						e.setPartsNameD(partsNames.get(3));
						e.setPartsNameE(partsNames.get(4));
					}
					e.setLastPartsNames(partsNames.get(partsNames.size() - 1));
					e.setPartsLevel(partsIds.size());

					if(MaintainPlanContentEnum.MAINTAIN_PARTS.getId() == planType && finalPlanGroup.containsKey(e.getPlanId())){
						e.setRelationWxPlanIds(finalPlanGroup.get(e.getPlanId()).stream().map(k -> String.valueOf(k.getFromPlanId())).distinct().collect(Collectors.joining(",")));
					}
				}
			});
		}
		return resultList;
	}

	@Override
	public List<BILarkRescueCountSourceVO> getGalaxyRescueResource(Date startDate, Date endDate) {
		return planContentService.getGalaxyRescueResource(startDate, endDate);
	}

	@Override
	public List<Map<String,Object>> selectWxFaultPlanList(Date startDate, Date endDate) {
		List<Map<String,Object>> resultMap = new ArrayList<>();
		List<BiWxPlanListDTO> list = planContentService.selectWxFaultPlanList(startDate,endDate);
		if(Func.isNotEmpty(list)){
			list.forEach(e -> {
				Map<String,Object> map = new HashMap<>();
				map.put("故障风险等级",this.getWxFaultLevelStr(e.getFaultLevel()));
				map.put("故障风险标签",Convert.toStr(e.getFaultLabel(),"-"));
//				DateUtil.format(e.getPlanCreateTime(),"yyyy/MM/dd HH:mm");
				map.put("风险预警时间",e.getPlanCreateTime().getTime());
				map.put("电梯编号",e.getElevatorId());
				map.put("电梯名称",e.getElevatorAddress());
				map.put("项目名称",e.getBuildingName());
				map.put("所属维保组",Convert.toStr(e.getElevatorDeptNames(),"-"));
				map.put("风险关闭时长要求",Func.isNotEmpty(e.getFaultOvertime()) ? String.format("%s天",e.getFaultOvertime()) : "-");
				if(e.getFaultLevel() == 5){
					map.put("处理建议","请根据现场情况判断是否申请技术支持");
				}else if(e.getFaultLevel() == 4){
					map.put("处理建议","请及时调度技术支持,并根据现场情况判断是否调度专家前往");
				}else  if(e.getFaultLevel() < 4){
					map.put("处理建议","请及时调度专家前往");
				}
				map.put("风险处理进展",TaskStatusEnum.getTaskName(MaintainPlanContentEnum.MAINTAIN_WX.getId(), e.getPlanStatus()));
				map.put("风险关闭时间",Func.isNotEmpty(e.getPlanEndTime()) ? DateUtil.format(e.getPlanEndTime(),"yyyy/MM/dd HH:mm") : "-");
				map.put("风险关闭是否超时","否");
				if(Func.isNotEmpty(e.getFaultOvertime())){
					Date date = DateUtil.offsetDay(e.getPlanCreateTime(),e.getFaultOvertime());
					if(Func.isNotEmpty(e.getPlanEndTime())){
						map.put("风险关闭是否超时",e.getPlanEndTime().getTime() > date.getTime() ? "是" : "否");
					}else {
						map.put("风险关闭是否超时",DateUtil.date().getTime() > date.getTime() ? "是" : "否");
					}
				}
				map.put("风险处理人",e.getPlanUserName());
				map.put("是否调度技术支持/专家",Func.isNotEmpty(e.getPlanUserRoleNames()) ? "是" : "否");
				map.put("技术支持/专家姓名",Convert.toStr(e.getPlanUserRoleNames(),"-"));
				map.put("风险关联电梯ID",String.valueOf(e.getPlanId()));
				resultMap.add(map);
			});
		}
		return resultMap;
	}

	@Override
	public List<Map<String, Object>> selectWxFaultPlanCount(Date startDate, Date endDate) {
		List<Map<String,Object>> resultMap = new ArrayList<>();
		List<DateTime> dateTimes = DateUtil.rangeToList(startDate,endDate,DateField.DAY_OF_YEAR);
		List<String> dateList = new ArrayList<>();
		dateTimes.forEach(e -> dateList.add(DateUtil.format(e,"yyyy/MM/dd")));
		List<BiWxPlanListDTO> list = planContentService.selectWxFaultPlanListAll(startDate,endDate);
		if(Func.isNotEmpty(dateList)){
			dateList.sort(Comparator.reverseOrder());
			dateList.forEach(e -> {
				Map<String,Object> map = new HashMap<>();
				String dateFormat = String.format("%s 17:00", e);
				// 将date format 转为date
				Date date = DateUtil.parse(dateFormat);
				map.put("日期",date.getTime());
				map.put("当日新增风险事件",list.stream().filter(t -> DateUtil.format(t.getPlanCreateTime(),"yyyy/MM/dd").equals(e)).map(BiWxPlanListDTO::getPlanId).distinct().count());
				map.put("截止当前待处理事件",list.stream().filter(t -> DateUtil.parse(DateUtil.formatDate(t.getPlanCreateTime())).getTime() <= DateUtil.parse(e,"yyyy/MM/dd").getTime()
						&& t.getPlanStatus().equals(TaskStatusEnum.WX_TO_START.getStatus()))
					.map(BiWxPlanListDTO::getPlanId).distinct().count());
				map.put("截止当前处理中事件",list.stream().filter(t -> DateUtil.parse(DateUtil.formatDate(t.getPlanCreateTime())).getTime() <= DateUtil.parse(e,"yyyy/MM/dd").getTime()
						&& t.getPlanStatus().equals(TaskStatusEnum.WX_UNDER_WAY.getStatus()))
					.map(BiWxPlanListDTO::getPlanId).distinct().count());
				map.put("截止当前关闭超时事件（非已关闭）",list.stream().filter(t -> DateUtil.parse(DateUtil.formatDate(t.getPlanCreateTime())).getTime() <= DateUtil.parse(e,"yyyy/MM/dd").getTime()
						&& !t.getPlanStatus().equals(TaskStatusEnum.WX_SIGN_FINISH.getStatus())
						&& Func.isNotEmpty(t.getFaultOvertime()) && DateUtil.offsetDay(t.getPlanCreateTime(),t.getFaultOvertime()).getTime() < DateUtil.date().getTime())
					.map(BiWxPlanListDTO::getPlanId).distinct().count());
				map.put("截止当前已关闭事件",list.stream().filter(t -> DateUtil.parse(DateUtil.formatDate(t.getPlanCreateTime())).getTime() <= DateUtil.parse(e,"yyyy/MM/dd").getTime()
						&& t.getPlanStatus().equals(TaskStatusEnum.WX_SIGN_FINISH.getStatus()))
					.map(BiWxPlanListDTO::getPlanId).distinct().count());
				resultMap.add(map);
			});
		}
		return resultMap;
	}

	private String getWxFaultLevelStr(Integer faultLevel) {
		switch (faultLevel){
			case 1:
				return "一级事件";
			case 2:
				return "二级事件";
			case 3:
				return "三级事件";
			case 4:
				return "四级事件";
			case 5:
				return "五级事件";
			case 6:
				return "六级事件";
			default:return "-";
		}
	}

	@Override
	public List<Map<String,String>> downWxHealthIndexExcelForLark(Date startDate, Date endDate, Integer dateType, List<List<String>> rows) {
		List<String> title = CollUtil.newArrayList
			("日期","监控梯台数","维修工单数","超3小时停梯维修工单数","维修工单关闭总时长","停梯故障维修工单数");
		rows.add(title);
		List<String> dateList = new ArrayList<>(6);
		List<Map<String,String>> initList = new ArrayList<>();
		if (dateType.equals(2)) {
			startDate = DateUtil.beginOfWeek(startDate);
			endDate = DateUtil.endOfWeek(endDate);
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/MM/dd"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/MM/dd"));
				if (!dateList.contains(weekDate)) {
					dateList.add(weekDate);
				}
			});
		} else if (dateType.equals(3)) {
			startDate = DateUtil.beginOfMonth(startDate);
			endDate = DateUtil.endOfMonth(endDate);
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = DateUtil.format(date, "yyyy/MM");
				if (!dateList.contains(monthDate)) {
					dateList.add(monthDate);
				}
			});
		}
		dateList.forEach(e -> {
			Map<String,String> map = new HashMap<>();
			title.forEach(j -> {
				if(j.equals("日期")){
					map.put(j,e);
				}else {
					map.put(j,"0");
				}
			});
			initList.add(map);
		});
		List<BiWxPlanListDTO> planList = planContentService.selectBiWxPlanList(startDate,endDate);
		List<ElevatorEffectedVO> elevatorEffectedList = planContentService.selectElevatorEffectedListByDate(startDate, endDate);
		if (ObjectUtil.isNotEmpty(elevatorEffectedList)) {
			Map<String, List<ElevatorEffectedVO>> dateGroup;
			if (dateType.equals(1)) {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/MM/dd")));
			} else if (dateType.equals(2)) {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/MM/dd"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/MM/dd"))));
			} else {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/MM")));
			}
			initList.forEach(e -> dateGroup.forEach((k, v) -> {
				if (e.get("日期").equals(k)){
					e.put("监控梯台数",String.valueOf(v.stream().map(ElevatorEffectedVO::getElevatorId).distinct().count()));
				}
			}));
		}
		if (ObjectUtil.isNotEmpty(planList)) {
			List<ElevatorSimpleInfoVO> elevatorStopByPlanList = planContentService.selectElevatorStopByPlan(planList.stream().map(BiWxPlanListDTO::getPlanId).collect(Collectors.toList()));
			Map<String, List<BiWxPlanListDTO>> dateGroup;
			if (dateType.equals(1)) {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/MM/dd")));
			} else if (dateType.equals(2)) {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/MM/dd"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/MM/dd"))));
			} else {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/MM")));
			}
			initList.forEach(e -> dateGroup.forEach((k, v) -> {
				if (e.get("日期").equals(k)){
					List<String> allUserIds = new ArrayList<>();
					v.forEach(t -> allUserIds.addAll(Func.toStrList(t.getPlanUserIds())));
					List<String> allUserRoleCodes = new ArrayList<>();
					v.forEach(t -> allUserRoleCodes.addAll(Func.toStrList("~",t.getPlanUserIdAndRoleCodes())));
					e.put("维修工单数",String.valueOf(v.stream().map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("超3小时停梯维修工单数",String.valueOf(v.stream().filter(t -> {
						ElevatorSimpleInfoVO elevatorSimpleInfoVO = elevatorStopByPlanList.stream().filter(o -> o.getModule().equals(String.valueOf(t.getPlanId()))).findFirst().orElse(null);
						if(Func.isNotEmpty(elevatorSimpleInfoVO)
							&& Func.isNotEmpty(elevatorSimpleInfoVO.getElevatorStopDuration())
							&& elevatorSimpleInfoVO.getElevatorStopDuration() > 3*60*60){
							return Boolean.TRUE;
						}
						return Boolean.FALSE;
					}).map(BiWxPlanListDTO::getPlanId).distinct().count()));
					// 计算维修工单关闭总时长，v的所有元素，getPlanEndTime()和getPlanCreateTime()都不为空的情况下，计算每一个getPlanCreateTime()-getPlanEndTime()的差值，然后求和
					long totalTime = v.stream()
						.filter(t -> !Func.isNull(t.getPlanEndTime()) && !Func.isNull(t.getPlanCreateTime()))
						.mapToLong(t -> t.getPlanEndTime().getTime() - t.getPlanCreateTime().getTime())
						.sum();
					// 转换为小时
					e.put("维修工单关闭总时长", String.valueOf(totalTime/1000/60/60L));
					e.put("停梯故障维修工单数", String.valueOf(
						v.stream().filter(t -> {
								ElevatorSimpleInfoVO elevatorSimpleInfoVO = elevatorStopByPlanList.stream().filter(o -> o.getModule().equals(String.valueOf(t.getPlanId()))).findFirst().orElse(null);
								if(Func.isNotEmpty(elevatorSimpleInfoVO)
									&& Func.isNotEmpty(elevatorSimpleInfoVO.getElevatorStopDuration())){
									return Boolean.TRUE;
								}
								return Boolean.FALSE;
						}).map(BiWxPlanListDTO::getPlanId).distinct().count())
					);
					e.put("参与维修员人数",String.valueOf(allUserRoleCodes.stream().filter(t -> t.contains("repair")).distinct().count()));
					e.put("参与保养员人数",String.valueOf(allUserRoleCodes.stream().filter(t -> t.contains("maintenance")).distinct().count()));
					e.put("参与维修人次",String.valueOf(v.stream().mapToInt(t -> Func.toStrList(t.getPlanUserIds()).size()).sum()));
					e.put("2人及以上参与工单数",String.valueOf(v.stream().filter(t -> Func.toStrList(t.getPlanUserIds()).stream().distinct().count() >= 2).map(BiWxPlanListDTO::getPlanId).distinct().count()));
					// 获取所有工单关闭时长计算中位数
					e.put("故障关闭时长中位数","0");
					List<Long> planTotalTimeList = v.stream().filter(t -> t.getPlanStatus().equals(TaskStatusEnum.WX_SIGN_FINISH.getStatus()))
						.map(t -> t.getPlanEndTime().getTime() - t.getPlanCreateTime().getTime()).sorted().collect(Collectors.toList());
					if (Func.isNotEmpty(planTotalTimeList)) {
						long med;
						int index = planTotalTimeList.size() / 2;
						if (planTotalTimeList.size() % 2 == 0) {
							med = BigDecimal.valueOf(planTotalTimeList.get(index - 1) + planTotalTimeList.get(index)).divide(BigDecimal.valueOf(2), 1, RoundingMode.HALF_UP).longValue();
						} else {
							med = planTotalTimeList.get(index);
						}
						e.put("故障关闭时长中位数",BigDecimal.valueOf(med).divide(BigDecimal.valueOf(1000*60*60),2,RoundingMode.HALF_UP).toString());
					}
					// 获取所有工单到达时长计算中位数
					Long totalArriveDuration = v.stream().filter(t -> !t.getPlanStatus().equals(TaskStatusEnum.WX_TO_START.getStatus()))
						.mapToLong(BiWxPlanListDTO::getPlanArriveDuration).sum();
					List<Long> planArriveDurationList = v.stream().filter(t -> !t.getPlanStatus().equals(TaskStatusEnum.WX_TO_START.getStatus()))
						.map(BiWxPlanListDTO::getPlanArriveDuration).sorted().collect(Collectors.toList());
					e.put("维修工单到场总时长", String.valueOf(BigDecimal.valueOf(totalArriveDuration).divide(BigDecimal.valueOf(1000*60*60),1,RoundingMode.HALF_UP)));
					e.put("故障到场时长中位数", "0");
					if (Func.isNotEmpty(planArriveDurationList)) {
						long med;
						int index = planArriveDurationList.size() / 2;
						if (planArriveDurationList.size() % 2 == 0) {
							med = BigDecimal.valueOf(planArriveDurationList.get(index - 1) + planArriveDurationList.get(index)).divide(BigDecimal.valueOf(2), 1, RoundingMode.HALF_UP).longValue();
						} else {
							med = planArriveDurationList.get(index);
						}
						e.put("故障到场时长中位数",BigDecimal.valueOf(med).divide(BigDecimal.valueOf(1000*60*60),1,RoundingMode.HALF_UP).toString());
					}
					// 获取所有工单作业时长计算中位数
					Long totalWorkTime = v.stream().filter(t -> t.getPlanStatus().equals(TaskStatusEnum.WX_SIGN_FINISH.getStatus())).mapToLong(BiWxPlanListDTO::getPlanWorkMinute).sum();
					List<Integer> planWorkTimeList = v.stream().filter(t -> t.getPlanStatus().equals(TaskStatusEnum.WX_SIGN_FINISH.getStatus())).map(BiWxPlanListDTO::getPlanWorkMinute).sorted().collect(Collectors.toList());
					e.put("维修工单作业总时长", String.valueOf(BigDecimal.valueOf(totalWorkTime).divide(BigDecimal.valueOf(60),1,RoundingMode.HALF_UP)));
					e.put("故障作业时长中位数", "0");
					if (Func.isNotEmpty(planWorkTimeList)) {
						long med;
						int index = planWorkTimeList.size() / 2;
						if (planWorkTimeList.size() % 2 == 0) {
							med = BigDecimal.valueOf(planWorkTimeList.get(index - 1) + planWorkTimeList.get(index)).divide(BigDecimal.valueOf(2), 1, RoundingMode.HALF_UP).longValue();
						} else {
							med = planWorkTimeList.get(index);
						}
						e.put("故障作业时长中位数",BigDecimal.valueOf(med).divide(BigDecimal.valueOf(60),1,RoundingMode.HALF_UP).toString());
					}
				}
			}));
		}
		List<Map<String,String>> resultMap = new ArrayList<>();
		initList.forEach(e -> {
			Map<String,String> larkMap = new HashMap<>(6);
			List<String> row = new ArrayList<>();
			row.add(e.get("日期"));
			larkMap.put("日期", e.get("日期"));
			row.add(e.get("监控梯台数"));
			larkMap.put("监控梯台数", String.valueOf(e.get("监控梯台数")));
			row.add(e.get("维修工单数"));
			larkMap.put("故障维修工单数", String.valueOf(e.get("维修工单数")));
			row.add(e.get("超3小时停梯维修工单数"));
			larkMap.put("停梯超3h维修工单数", String.valueOf(e.get("超3小时停梯维修工单数")));
			row.add(e.get("维修工单关闭总时长"));
			larkMap.put("维修工单关闭总时长", String.valueOf(e.get("维修工单关闭总时长")));
			row.add(e.get("停梯故障维修工单数"));
			larkMap.put("停梯故障维修工单数", String.valueOf(e.get("停梯故障维修工单数")));

			larkMap.put("参与维修员人数", String.valueOf(e.get("参与维修员人数")));
			larkMap.put("参与保养员人数", String.valueOf(e.get("参与保养员人数")));
			larkMap.put("参与维修人次", String.valueOf(e.get("参与维修人次")));
			larkMap.put("2人及以上参与工单数", String.valueOf(e.get("2人及以上参与工单数")));
			larkMap.put("故障关闭时长中位数", String.valueOf(e.get("故障关闭时长中位数")));
			larkMap.put("维修工单到场总时长", String.valueOf(e.get("维修工单到场总时长")));
			larkMap.put("故障到场时长中位数", String.valueOf(e.get("故障到场时长中位数")));
			larkMap.put("维修工单作业总时长", String.valueOf(e.get("维修工单作业总时长")));
			larkMap.put("故障作业时长中位数", String.valueOf(e.get("故障作业时长中位数")));
			resultMap.add(larkMap);
			rows.add(row);
		});
		return resultMap;
	}

	@Override
	public void downWxHealthIndexExcel(Date startDate, Date endDate, Integer dateType, List<List<String>> rows) {
		List<String> title = CollUtil.newArrayList
			("日期","监控梯台数","故障电梯数", "维修工单数", "参与总人数",
				"维修员与保养员参与人数", "参与维修员人数", "参与保养员人数",
				"其他参与人数", "维修员参与工单数", "保养员参与工单数",
				"维修员与保养员共同参与工单数", "仅维修人员参与工单数",
				"实际2人作业以上工单数", "超1小时到达工单数", "超1.5小时作业工时工单数",
				"面向客户超4小时工单数", "超3小时停梯维修工单数");
		rows.add(title);
		List<String> dateList = new ArrayList<>(32);
		List<Map<String,String>> initList = new ArrayList<>();
		if (dateType.equals(2)) {
			startDate = DateUtil.beginOfWeek(startDate);
			endDate = DateUtil.endOfWeek(endDate);
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
				if (!dateList.contains(weekDate)) {
					dateList.add(weekDate);
				}
			});
		} else if (dateType.equals(3)) {
			startDate = DateUtil.beginOfMonth(startDate);
			endDate = DateUtil.endOfMonth(endDate);
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = DateUtil.format(date, "yyyy/M");
				if (!dateList.contains(monthDate)) {
					dateList.add(monthDate);
				}
			});
		}
		dateList.forEach(e -> {
			Map<String,String> map = new HashMap<>();
			title.forEach(j -> {
				if(j.equals("日期")){
					map.put(j,e);
				}else {
					map.put(j,"0");
				}
			});
			initList.add(map);
		});
		List<BiWxPlanListDTO> planList = planContentService.selectBiWxPlanList(startDate,endDate);
		List<ElevatorEffectedVO> elevatorEffectedList = planContentService.selectElevatorEffectedListByDate(startDate, endDate);
		if (ObjectUtil.isNotEmpty(elevatorEffectedList)) {
			Map<String, List<ElevatorEffectedVO>> dateGroup;
			if (dateType.equals(1)) {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d")));
			} else if (dateType.equals(2)) {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
			} else {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M")));
			}
			initList.forEach(e -> dateGroup.forEach((k, v) -> {
				if (e.get("日期").equals(k)){
					e.put("监控梯台数",String.valueOf(v.stream().map(ElevatorEffectedVO::getElevatorId).distinct().count()));
				}
			}));
		}
		if (ObjectUtil.isNotEmpty(planList)) {
			List<ElevatorSimpleInfoVO> elevatorStopByPlanList = planContentService.selectElevatorStopByPlan(planList.stream().map(BiWxPlanListDTO::getPlanId).collect(Collectors.toList()));
			Map<String, List<BiWxPlanListDTO>> dateGroup;
			if (dateType.equals(1)) {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d")));
			} else if (dateType.equals(2)) {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"))));
			} else {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M")));
			}
			initList.forEach(e -> dateGroup.forEach((k, v) -> {
				if (e.get("日期").equals(k)){
					List<String> allUserIds = new ArrayList<>();
					v.forEach(t -> allUserIds.addAll(Func.toStrList(t.getPlanUserIds())));
					List<String> allUserRoleCodes = new ArrayList<>();
					v.forEach(t -> allUserRoleCodes.addAll(Func.toStrList("~",t.getPlanUserIdAndRoleCodes())));
					e.put("故障电梯数",String.valueOf(v.stream().map(BiWxPlanListDTO::getElevatorId).distinct().count()));
					e.put("维修工单数",String.valueOf(v.stream().map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("参与总人数",String.valueOf(allUserIds.stream().distinct().count()));
					e.put("维修员与保养员参与人数",String.valueOf(allUserRoleCodes.stream().filter(t -> t.contains("maintenance") || t.contains("repair"))
						.map(t -> t.split(",")[0]).distinct().count()));
					e.put("参与维修员人数",String.valueOf(allUserRoleCodes.stream().filter(t -> t.contains("repair")).distinct().count()));
					e.put("参与保养员人数",String.valueOf(allUserRoleCodes.stream().filter(t -> t.contains("maintenance")).distinct().count()));
					e.put("其他参与人数",String.valueOf(allUserRoleCodes.stream().filter(t -> !t.contains("maintenance") && !t.contains("repair"))
						.map(t -> t.split(",")[0]).distinct().count()));
					e.put("维修员参与工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes()) && t.getPlanUserRoleCodes().contains("repair"))
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("保养员参与工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes()) && t.getPlanUserRoleCodes().contains("maintenance"))
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("维修员与保养员共同参与工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes())
							&& t.getPlanUserRoleCodes().contains("maintenance")
							&& t.getPlanUserRoleCodes().contains("repair"))
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("仅维修人员参与工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes())
							&& Func.toStrList(t.getPlanUserRoleCodes()).stream().distinct().count() == 1
							&& t.getPlanUserRoleCodes().contains("repair"))
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("实际2人作业以上工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserIds())
							&& Func.toStrList(t.getPlanUserIds()).stream().distinct().count() >= 2)
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("超1小时到达工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanArriveDuration())
							&& t.getPlanArriveDuration() > 60 * 60 * 1000)
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("超1.5小时作业工时工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanWorkMinute())
							&& t.getPlanWorkMinute() > 1.5*60)
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("面向客户超4小时工单数",String.valueOf(v.stream().filter(t -> {
						if (t.getPlanStatus() == TaskStatusEnum.WX_SIGN_FINISH.getStatus()){
							if(t.getPlanEndTime().getTime() - t.getPlanCreateTime().getTime() > 4*60*60*1000){
								return Boolean.TRUE;
							}
						}else {
							if(DateUtil.date().getTime() - t.getPlanCreateTime().getTime() > 4*60*60*1000){
								return Boolean.TRUE;
							}
						}
						return Boolean.FALSE;
					}).map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("超3小时停梯维修工单数",String.valueOf(v.stream().filter(t -> {
						ElevatorSimpleInfoVO elevatorSimpleInfoVO = elevatorStopByPlanList.stream().filter(o -> o.getModule().equals(String.valueOf(t.getPlanId()))).findFirst().orElse(null);
						if(Func.isNotEmpty(elevatorSimpleInfoVO)
							&& Func.isNotEmpty(elevatorSimpleInfoVO.getElevatorStopDuration())
							&& elevatorSimpleInfoVO.getElevatorStopDuration() > 3*60*60){
							return Boolean.TRUE;
						}
						return Boolean.FALSE;
					}).map(BiWxPlanListDTO::getPlanId).distinct().count()));
				}
			}));
		}
		initList.forEach(e -> {
			List<String> row = new ArrayList<>();
			row.add(e.get("日期"));
			row.add(e.get("监控梯台数"));
			row.add(e.get("故障电梯数"));
			row.add(e.get("维修工单数"));
			row.add(e.get("参与总人数"));
			row.add(e.get("维修员与保养员参与人数"));
			row.add(e.get("参与维修员人数"));
			row.add(e.get("参与保养员人数"));
			row.add(e.get("其他参与人数"));
			row.add(e.get("维修员参与工单数"));
			row.add(e.get("保养员参与工单数"));
			row.add(e.get("维修员与保养员共同参与工单数"));
			row.add(e.get("仅维修人员参与工单数"));
			row.add(e.get("实际2人作业以上工单数"));
			row.add(e.get("超1小时到达工单数"));
			row.add(e.get("超1.5小时作业工时工单数"));
			row.add(e.get("面向客户超4小时工单数"));
			row.add(e.get("超3小时停梯维修工单数"));
			rows.add(row);
		});
	}

	@Override
	public void downWxWorkTimeExcel(Date startDate, Date endDate, Integer dateType, List<List<String>> rows) {
		List<String> title = CollUtil.newArrayList
			("日期","监控梯台数","故障电梯数", "维修工单数", "参与总人数",
				"维修员与保养员参与人数", "参与维修员人数", "参与保养员人数",
				"其他参与人数", "维修员参与工单数", "保养员参与工单数",
				"维修员与保养员共同参与工单数", "仅维修人员参与工单数",
				"全部工时按人员", "全部工时按工单",
				"到达工时按人员", "到达工时按工单",
				"全部作业工时", "维修员全部工时按人员",
				"维修员全部工时按工单", "维修员全部到达工时按人员",
				"维修员全部到达工时按工单", "仅维修员全部作业工时"
			);
		rows.add(title);
		List<String> dateList = new ArrayList<>(32);
		List<Map<String,String>> initList = new ArrayList<>();
		if (dateType.equals(2)) {
			startDate = DateUtil.beginOfWeek(startDate);
			endDate = DateUtil.endOfWeek(endDate);
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
				if (!dateList.contains(weekDate)) {
					dateList.add(weekDate);
				}
			});
		} else if (dateType.equals(3)) {
			startDate = DateUtil.beginOfMonth(startDate);
			endDate = DateUtil.endOfMonth(endDate);
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = DateUtil.format(date, "yyyy/M");
				if (!dateList.contains(monthDate)) {
					dateList.add(monthDate);
				}
			});
		}
		dateList.forEach(e -> {
			Map<String,String> map = new HashMap<>();
			title.forEach(j -> {
				if(j.equals("日期")){
					map.put(j,e);
				}else {
					map.put(j,"0");
				}
			});
			initList.add(map);
		});
		List<BiWxPlanListDTO> planList = planContentService.selectBiWxPlanList(startDate,endDate);
		List<ElevatorEffectedVO> elevatorEffectedList = planContentService.selectElevatorEffectedListByDate(startDate, endDate);
		if (ObjectUtil.isNotEmpty(elevatorEffectedList)) {
			Map<String, List<ElevatorEffectedVO>> dateGroup;
			if (dateType.equals(1)) {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d")));
			} else if (dateType.equals(2)) {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
			} else {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M")));
			}
			initList.forEach(e -> dateGroup.forEach((k, v) -> {
				if (e.get("日期").equals(k)){
					e.put("监控梯台数",String.valueOf(v.stream().map(ElevatorEffectedVO::getElevatorId).distinct().count()));
				}
			}));
		}
		if (ObjectUtil.isNotEmpty(planList)) {
//			List<ElevatorSimpleInfoVO> elevatorStopByPlanList = planContentService.selectElevatorStopByPlan(planList.stream().map(BiWxPlanListDTO::getPlanId).collect(Collectors.toList()));
			List<BiWxPlanListDTO> planUserList = planContentService.selectBiWxPlanUserList(planList.stream().map(BiWxPlanListDTO::getPlanId).collect(Collectors.toList()));
			Map<String, List<BiWxPlanListDTO>> dateGroup;
			Map<String, List<BiWxPlanListDTO>> planUserDateGroup;
			if (dateType.equals(1)) {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d")));
				planUserDateGroup = planUserList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d")));
			} else if (dateType.equals(2)) {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"))));
				planUserDateGroup = planUserList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"))));
			} else {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M")));
				planUserDateGroup = planUserList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M")));
			}
			initList.forEach(e -> {
				List<BiWxPlanListDTO> v = dateGroup.get(e.get("日期"));
				if (Func.isNotEmpty(v)){
					v = v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes())
						&& (t.getPlanUserRoleCodes().contains("maintenance") || t.getPlanUserRoleCodes().contains("repair"))).collect(Collectors.toList());
					List<String> allUserIds = new ArrayList<>();
					v.forEach(t -> allUserIds.addAll(Func.toStrList(t.getPlanUserIds())));
					List<String> allUserRoleCodes = new ArrayList<>();
					v.forEach(t -> allUserRoleCodes.addAll(Func.toStrList("~",t.getPlanUserIdAndRoleCodes())));
					e.put("故障电梯数",String.valueOf(v.stream().map(BiWxPlanListDTO::getElevatorId).distinct().count()));
					e.put("维修工单数",String.valueOf(v.stream().map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("参与总人数",String.valueOf(allUserIds.stream().distinct().count()));
					e.put("维修员与保养员参与人数",String.valueOf(allUserRoleCodes.stream().filter(t -> t.contains("maintenance") || t.contains("repair"))
						.map(t -> t.split(",")[0]).distinct().count()));
					e.put("参与维修员人数",String.valueOf(allUserRoleCodes.stream().filter(t -> t.contains("repair")).distinct().count()));
					e.put("参与保养员人数",String.valueOf(allUserRoleCodes.stream().filter(t -> t.contains("maintenance")).distinct().count()));
					e.put("其他参与人数",String.valueOf(allUserRoleCodes.stream().filter(t -> !t.contains("maintenance") && !t.contains("repair"))
						.map(t -> t.split(",")[0]).distinct().count()));
					e.put("维修员参与工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes()) && t.getPlanUserRoleCodes().contains("repair"))
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("保养员参与工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes()) && t.getPlanUserRoleCodes().contains("maintenance"))
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("维修员与保养员共同参与工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes())
							&& t.getPlanUserRoleCodes().contains("maintenance")
							&& t.getPlanUserRoleCodes().contains("repair"))
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("仅维修人员参与工单数",String.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes())
							&& Func.toStrList(t.getPlanUserRoleCodes()).stream().distinct().count() == 1
							&& t.getPlanUserRoleCodes().contains("repair"))
						.map(BiWxPlanListDTO::getPlanId).distinct().count()));
				}
				List<BiWxPlanListDTO> v2 = planUserDateGroup.get(e.get("日期"));
				if (Func.isNotEmpty(v2)){
					e.put("全部工时按人员",BigDecimal.valueOf(v2.stream().filter(t -> Func.isNotEmpty(t.getPlanUserFirstSignTime())).mapToDouble(t ->
							BigDecimal.valueOf(t.getPlanUserWorkMinute())
								.add(BigDecimal.valueOf(t.getPlanUserFirstSignTime().getTime() - t.getPlanUserCreateTime().getTime())
									.divide(BigDecimal.valueOf(60*1000),2, RoundingMode.HALF_UP)).doubleValue()).sum())
						.divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString());
					e.put("全部工时按工单",String.valueOf(
						BigDecimal.valueOf(v.stream().mapToDouble(t -> BigDecimal.valueOf(t.getPlanArriveDuration()).divide(BigDecimal.valueOf(60*1000),2,RoundingMode.HALF_UP).doubleValue()).sum()
						).add(BigDecimal.valueOf(
							v2.stream().mapToInt(BiWxPlanListDTO::getPlanUserWorkMinute).sum()
						)).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
					e.put("到达工时按人员",String.valueOf(
						BigDecimal.valueOf(v2.stream().filter(t -> Func.isNotEmpty(t.getPlanUserFirstSignTime())).mapToDouble(t ->
							BigDecimal.valueOf(t.getPlanUserFirstSignTime().getTime() - t.getPlanUserCreateTime().getTime())
								.divide(BigDecimal.valueOf(60*1000),2, RoundingMode.HALF_UP).doubleValue()).sum())
							.divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
					e.put("到达工时按工单",String.valueOf(
						BigDecimal.valueOf(v.stream().mapToDouble(t -> BigDecimal.valueOf(t.getPlanArriveDuration()).divide(BigDecimal.valueOf(60*1000),2,RoundingMode.HALF_UP).doubleValue()).sum()
						).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
					e.put("全部作业工时",String.valueOf(
						BigDecimal.valueOf(v2.stream().mapToInt(BiWxPlanListDTO::getPlanUserWorkMinute).sum()
						).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
					e.put("维修员全部工时按人员",String.valueOf(
						BigDecimal.valueOf(v2.stream().filter(t -> t.getPlanUserRoleCodes().contains("repair") && Func.isNotEmpty(t.getPlanUserFirstSignTime())).mapToDouble(t ->
								BigDecimal.valueOf(t.getPlanUserWorkMinute())
									.add(BigDecimal.valueOf(t.getPlanUserFirstSignTime().getTime() - t.getPlanUserCreateTime().getTime())
										.divide(BigDecimal.valueOf(60*1000),2, RoundingMode.HALF_UP)).doubleValue()).sum())
							.divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
					// 获取每个工单第一个签到的维修员-
					List<BiWxPlanListDTO> allPlanFirstRepair = new ArrayList<>();
					v2.stream().collect(Collectors.groupingBy(BiWxPlanListDTO::getPlanId)).forEach((k,v3) -> {
						v3 = v3.stream().filter(t -> Func.isNotEmpty(t.getPlanUserRoleCodes()) && t.getPlanUserRoleCodes().contains("repair") && Func.isNotEmpty(t.getPlanUserFirstSignTime())).sorted(Comparator.comparing(BiWxPlanListDTO::getPlanUserFirstSignTime)).collect(Collectors.toList());
						if(Func.isNotEmpty(v3)){
							allPlanFirstRepair.add(v3.get(0));
						}
					});
					e.put("维修员全部工时按工单",String.valueOf(
						BigDecimal.valueOf(
							allPlanFirstRepair.stream().filter(t -> Func.isNotEmpty(t.getPlanUserFirstSignTime())).mapToDouble(t ->
								BigDecimal.valueOf(t.getPlanUserFirstSignTime().getTime() - t.getPlanUserCreateTime().getTime())
									.divide(BigDecimal.valueOf(60*1000),2,RoundingMode.HALF_UP).doubleValue()).sum()
							).add(BigDecimal.valueOf(v2.stream().filter(t -> t.getPlanUserRoleCodes().contains("repair"))
							.mapToInt(BiWxPlanListDTO::getPlanUserWorkMinute).sum()))
							.divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
					e.put("维修员全部到达工时按人员",String.valueOf(
						BigDecimal.valueOf(v2.stream().filter(t -> t.getPlanUserRoleCodes().contains("repair") && Func.isNotEmpty(t.getPlanUserFirstSignTime())).mapToDouble(t ->
								BigDecimal.valueOf(t.getPlanUserFirstSignTime().getTime() - t.getPlanUserCreateTime().getTime())
									.divide(BigDecimal.valueOf(60*1000),2, RoundingMode.HALF_UP).doubleValue()).sum())
							.divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
					e.put("维修员全部到达工时按工单",String.valueOf(
						BigDecimal.valueOf(
							allPlanFirstRepair.stream().filter(t -> Func.isNotEmpty(t.getPlanUserFirstSignTime())).mapToDouble(t ->
								BigDecimal.valueOf(t.getPlanUserFirstSignTime().getTime() - t.getPlanUserCreateTime().getTime())
									.divide(BigDecimal.valueOf(60*1000),2,RoundingMode.HALF_UP).doubleValue()).sum()
						).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
					e.put("仅维修员全部作业工时",String.valueOf(
						BigDecimal.valueOf(v2.stream().filter(t -> t.getPlanUserRoleCodes().contains("repair")).mapToDouble(BiWxPlanListDTO::getPlanUserWorkMinute).sum())
							.divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString()
					));
				}
			});

		}
		initList.forEach(e -> {
			List<String> row = new ArrayList<>();
			row.add(e.get("日期"));
			row.add(e.get("监控梯台数"));
			row.add(e.get("故障电梯数"));
			row.add(e.get("维修工单数"));
			row.add(e.get("参与总人数"));
			row.add(e.get("维修员与保养员参与人数"));
			row.add(e.get("参与维修员人数"));
			row.add(e.get("参与保养员人数"));
			row.add(e.get("其他参与人数"));
			row.add(e.get("维修员参与工单数"));
			row.add(e.get("保养员参与工单数"));
			row.add(e.get("维修员与保养员共同参与工单数"));
			row.add(e.get("仅维修人员参与工单数"));
			row.add(e.get("全部工时按人员"));
			row.add(e.get("全部工时按工单"));
			row.add(e.get("到达工时按人员"));
			row.add(e.get("到达工时按工单"));
			row.add(e.get("全部作业工时"));
			row.add(e.get("维修员全部工时按人员"));
			row.add(e.get("维修员全部工时按工单"));
			row.add(e.get("维修员全部到达工时按人员"));
			row.add(e.get("维修员全部到达工时按工单"));
			row.add(e.get("仅维修员全部作业工时"));
			rows.add(row);
		});
	}

	@Override
	public void downWxUserWorkTimeExcel(Date startDate, Date endDate, Integer dateType, List<List<String>> rows) {
		List<String> title = CollUtil.newArrayList
			("日期","姓名", "人员类型", "人员ID",
				"维修工单数","工时总数","作业工时总数","到达工时总数");
		rows.add(title);
		List<String> dateList = new ArrayList<>(32);
		List<Map<String,String>> initList = new ArrayList<>();
		if (dateType.equals(2)) {
			startDate = DateUtil.beginOfWeek(startDate);
			endDate = DateUtil.endOfWeek(endDate);
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
				if (!dateList.contains(weekDate)) {
					dateList.add(weekDate);
				}
			});
		} else if (dateType.equals(3)) {
			startDate = DateUtil.beginOfMonth(startDate);
			endDate = DateUtil.endOfMonth(endDate);
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = DateUtil.format(date, "yyyy/M");
				if (!dateList.contains(monthDate)) {
					dateList.add(monthDate);
				}
			});
		}
		List<BiWxPlanListDTO> planList = planContentService.selectBiWxPlanList(startDate,endDate);
		if (ObjectUtil.isNotEmpty(planList)) {
			List<BiWxPlanListDTO> planUserList = planContentService.selectBiWxPlanUserList(planList.stream().map(BiWxPlanListDTO::getPlanId).collect(Collectors.toList()));
			Map<String, List<BiWxPlanListDTO>> planUserDateGroup;
			if (dateType.equals(1)) {
				planUserDateGroup = planUserList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d")));
			} else if (dateType.equals(2)) {
				planUserDateGroup = planUserList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"))));
			} else {
				planUserDateGroup = planUserList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M")));
			}
			dateList.forEach(e -> {
				List<BiWxPlanListDTO> userDate = planUserDateGroup.get(e);
				if(Func.isNotEmpty(userDate)){
					Map<String,List<BiWxPlanListDTO>> userGroup = userDate.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s~%s", t.getUserId(),t.getPlanUserName(),t.getPlanUserRoleNames())));
					userGroup.forEach((k,v) -> {
						Map<String,String> map = new HashMap<>();
						map.put("日期",e);
						List<String> userInfo = Func.toStrList("~",k);
						map.put("姓名",userInfo.get(1));
						map.put("人员类型","-");
						if(userInfo.size() > 2){
							map.put("人员类型",userInfo.get(2));
						}
						map.put("人员ID",userInfo.get(0));
						map.put("维修工单数",String.valueOf(v.stream().mapToLong(BiWxPlanListDTO::getPlanId).distinct().count()));
						map.put("工时总数",BigDecimal.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserFirstSignTime())).mapToDouble(t ->
							BigDecimal.valueOf(t.getPlanUserWorkMinute())
								.add(BigDecimal.valueOf(t.getPlanUserFirstSignTime().getTime() - t.getPlanUserCreateTime().getTime())
									.divide(BigDecimal.valueOf(60*1000),2,RoundingMode.HALF_UP)).doubleValue()
						).sum()).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString());
						map.put("作业工时总数",BigDecimal.valueOf(v.stream().mapToInt(BiWxPlanListDTO::getPlanUserWorkMinute).sum()).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString());
						map.put("到达工时总数",BigDecimal.valueOf(v.stream().filter(t -> Func.isNotEmpty(t.getPlanUserFirstSignTime())).mapToDouble(t ->
							BigDecimal.valueOf(t.getPlanUserFirstSignTime().getTime() - t.getPlanUserCreateTime().getTime())
								.divide(BigDecimal.valueOf(60*1000),2,RoundingMode.HALF_UP).doubleValue()
						).sum()).divide(BigDecimal.valueOf(60),2,RoundingMode.HALF_UP).toString());
						initList.add(map);
					});
				}
			});
		}
		initList.forEach(e -> {
			List<String> row = new ArrayList<>();
			row.add(e.get("日期"));
			row.add(e.get("姓名"));
			row.add(e.get("人员类型"));
			row.add(e.get("人员ID"));
			row.add(e.get("维修工单数"));
			row.add(e.get("工时总数"));
			row.add(e.get("作业工时总数"));
			row.add(e.get("到达工时总数"));
			rows.add(row);
		});
	}

	@Override
	public void downWxElevatorDeptExcel(Date startDate, Date endDate, Integer dateType, List<List<String>> rows) {
		List<String> title = CollUtil.newArrayList
			("日期","维保组ID", "维保组名称", "责任梯台数","责任梯台数（在保非外包）",
				"维修工单数","客户报障工单数");
		rows.add(title);
		List<String> dateList = new ArrayList<>(32);
		List<Map<String,String>> initList = new ArrayList<>();
		if (dateType.equals(2)) {
			startDate = DateUtil.beginOfWeek(startDate);
			endDate = DateUtil.endOfWeek(endDate);
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
				if (!dateList.contains(weekDate)) {
					dateList.add(weekDate);
				}
			});
		} else if (dateType.equals(3)) {
			startDate = DateUtil.beginOfMonth(startDate);
			endDate = DateUtil.endOfMonth(endDate);
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = DateUtil.format(date, "yyyy/M");
				if (!dateList.contains(monthDate)) {
					dateList.add(monthDate);
				}
			});
		}

		List<BiWxPlanListDTO> planList = planContentService.selectElevatorDeptPlan(startDate,endDate);
		if(Func.isNotEmpty(planList)){
			dateList.forEach(e -> {
				Map<String,List<BiWxPlanListDTO>> deptGroup = planList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", t.getDeptId(),t.getDeptName())));
				deptGroup.forEach((k,v) -> {
					Map<String,String> map = new HashMap<>();
					map.put("日期",e);
					List<String> deptInfo = Func.toStrList("~",k);
					map.put("维保组ID",deptInfo.get(0));
					map.put("维保组名称",deptInfo.get(1));
					map.put("责任梯台数",String.valueOf(v.stream().map(BiWxPlanListDTO::getElevatorId).distinct().count()));
					map.put("责任梯台数（在保非外包）",String.valueOf(v.stream().filter(t -> (t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.CONTRACT_IN_TIME.getId())
					|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.CONTRACT_OUT_TIME.getId())
					|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_STOP.getId())
					|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_END.getId())
					|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_END_HAS_NEXT.getId())
					|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.DIS_ENABLE.getId()))
					&& t.getElevatorFromType().equals(2)).map(BiWxPlanListDTO::getElevatorId).distinct().count()));
					map.put("维修工单数",String.valueOf(v.stream().filter(t -> {
						if(Func.isNotEmpty(t.getPlanCreateTime())){
							String planCreateTime;
							if (dateType.equals(1)) {
								planCreateTime = DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d");
							} else if (dateType.equals(2)) {
								planCreateTime = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"));
							} else {
								planCreateTime = DateUtil.format(t.getPlanCreateTime(), "yyyy/M");
							}
							if(planCreateTime.equals(e)){
								return Boolean.TRUE;
							}
						}
						return Boolean.FALSE;
					}).map(BiWxPlanListDTO::getPlanId).distinct().count()));
					map.put("客户报障工单数",String.valueOf(v.stream().filter(t -> {
						if(Func.isNotEmpty(t.getPlanCreateTime())){
							String planCreateTime;
							if (dateType.equals(1)) {
								planCreateTime = DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d");
							} else if (dateType.equals(2)) {
								planCreateTime = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"));
							} else {
								planCreateTime = DateUtil.format(t.getPlanCreateTime(), "yyyy/M");
							}
							if(planCreateTime.equals(e) && Func.isNotEmpty(t.getWorkOrderType()) && WorkOrderTypeEnum.CLIENT.getId() == t.getWorkOrderType()){
								return Boolean.TRUE;
							}
						}
						return Boolean.FALSE;
					}).map(BiWxPlanListDTO::getPlanId).distinct().count()));
					initList.add(map);
				});
			});
		}
		initList.forEach(e -> {
			List<String> row = new ArrayList<>();
			row.add(e.get("日期"));
			row.add(e.get("维保组ID"));
			row.add(e.get("维保组名称"));
			row.add(e.get("责任梯台数"));
			row.add(e.get("责任梯台数（在保非外包）"));
			row.add(e.get("维修工单数"));
			row.add(e.get("客户报障工单数"));
			rows.add(row);
		});

	}

	@Override
	public void downWxElevatorUserExcel(Date startDate, Date endDate, Integer dateType, List<List<String>> rows) {
		List<String> title = CollUtil.newArrayList
			("日期","人员ID", "名字","技能等级", "人员类型",
				"所属区组","责任梯台数","责任梯台数（在保非外包）","维修工单数","客户报障工单数");
		rows.add(title);
		List<String> dateList = new ArrayList<>(32);
		List<Map<String,String>> initList = new ArrayList<>();
		if (dateType.equals(2)) {
			startDate = DateUtil.beginOfWeek(startDate);
			endDate = DateUtil.endOfWeek(endDate);
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
				if (!dateList.contains(weekDate)) {
					dateList.add(weekDate);
				}
			});
		} else if (dateType.equals(3)) {
			startDate = DateUtil.beginOfMonth(startDate);
			endDate = DateUtil.endOfMonth(endDate);
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = DateUtil.format(date, "yyyy/M");
				if (!dateList.contains(monthDate)) {
					dateList.add(monthDate);
				}
			});
		}

		List<BiWxPlanListDTO> planList = planContentService.selectElevatorUserPlan(startDate,endDate);
		if(Func.isNotEmpty(planList)){
			dateList.forEach(e -> {
				Map<Long,List<BiWxPlanListDTO>> userGroup = planList.stream().collect(Collectors.groupingBy(BiWxPlanListDTO::getUserId));
				userGroup.forEach((k,v) -> {
					BiWxPlanListDTO userInfo = v.get(0);
					Map<String,String> map = new HashMap<>();
					map.put("日期",e);
					map.put("人员ID",String.valueOf(userInfo.getUserId()));
					map.put("名字",userInfo.getPlanUserName());
					map.put("技能等级",userInfo.getUserLevelName());
					map.put("人员类型",userInfo.getPlanUserRoleNames());
					map.put("所属区组",userInfo.getDeptName());
					map.put("责任梯台数",String.valueOf(v.stream().map(BiWxPlanListDTO::getElevatorId).distinct().count()));
					map.put("责任梯台数（在保非外包）",String.valueOf(v.stream().filter(t -> (t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.CONTRACT_IN_TIME.getId())
						|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.CONTRACT_OUT_TIME.getId())
						|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_STOP.getId())
						|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_END.getId())
						|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.OUT_TIME_END_HAS_NEXT.getId())
						|| t.getElevatorMaintainStatus().equals(ElevatorMaintainStatusEnums.DIS_ENABLE.getId()))
						&& t.getElevatorFromType().equals(2)).map(BiWxPlanListDTO::getElevatorId).distinct().count()));
					map.put("维修工单数",String.valueOf(v.stream().filter(t -> {
						if(Func.isNotEmpty(t.getPlanCreateTime())){
							String planCreateTime;
							if (dateType.equals(1)) {
								planCreateTime = DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d");
							} else if (dateType.equals(2)) {
								planCreateTime = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"));
							} else {
								planCreateTime = DateUtil.format(t.getPlanCreateTime(), "yyyy/M");
							}
							if(planCreateTime.equals(e)){
								return Boolean.TRUE;
							}
						}
						return Boolean.FALSE;
					}).map(BiWxPlanListDTO::getPlanId).distinct().count()));
					map.put("客户报障工单数",String.valueOf(v.stream().filter(t -> {
						if(Func.isNotEmpty(t.getPlanCreateTime())){
							String planCreateTime;
							if (dateType.equals(1)) {
								planCreateTime = DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d");
							} else if (dateType.equals(2)) {
								planCreateTime = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"));
							} else {
								planCreateTime = DateUtil.format(t.getPlanCreateTime(), "yyyy/M");
							}
							if(planCreateTime.equals(e) && Func.isNotEmpty(t.getWorkOrderType()) && WorkOrderTypeEnum.CLIENT.getId() == t.getWorkOrderType()){
								return Boolean.TRUE;
							}
						}
						return Boolean.FALSE;
					}).map(BiWxPlanListDTO::getPlanId).distinct().count()));
					initList.add(map);
				});
			});
		}
		initList.forEach(e -> {
			List<String> row = new ArrayList<>();
			row.add(e.get("日期"));
			row.add(e.get("人员ID"));
			row.add(e.get("名字"));
			row.add(e.get("技能等级"));
			row.add(e.get("人员类型"));
			row.add(e.get("所属区组"));
			row.add(e.get("责任梯台数"));
			row.add(e.get("责任梯台数（在保非外包）"));
			row.add(e.get("维修工单数"));
			row.add(e.get("客户报障工单数"));
			rows.add(row);
		});
	}

	@Override
	public void downWxElevatorStopExcel(Date startDate, Date endDate, Integer dateType, List<List<String>> rows) {
		List<String> title = CollUtil.newArrayList
			("日期","监控梯台数", "报障工单数", "报障状态为停梯的工单数",
				"报障状态为停梯的电梯数");
		rows.add(title);
		List<String> dateList = new ArrayList<>(32);
		List<Map<String,String>> initList = new ArrayList<>();
		if (dateType.equals(2)) {
			startDate = DateUtil.beginOfWeek(startDate);
			endDate = DateUtil.endOfWeek(endDate);
			// 周
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.DAY_OF_YEAR);
			rangeDate.forEach(date -> {
				String weekDate = String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(date), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(date), "yyyy/M/d"));
				if (!dateList.contains(weekDate)) {
					dateList.add(weekDate);
				}
			});
		} else if (dateType.equals(3)) {
			startDate = DateUtil.beginOfMonth(startDate);
			endDate = DateUtil.endOfMonth(endDate);
			// 月
			List<DateTime> rangeDate = DateUtil.rangeToList(startDate, endDate, DateField.MONTH);
			rangeDate.forEach(date -> {
				String monthDate = DateUtil.format(date, "yyyy/M");
				if (!dateList.contains(monthDate)) {
					dateList.add(monthDate);
				}
			});
		}
		dateList.forEach(e -> {
			Map<String,String> map = new HashMap<>();
			title.forEach(j -> {
				if(j.equals("日期")){
					map.put(j,e);
				}else {
					map.put(j,"0");
				}
			});
			initList.add(map);
		});
		List<BiWxPlanListDTO> planList = planContentService.selectBiWxPlanList(startDate,endDate);
		List<ElevatorEffectedVO> elevatorEffectedList = planContentService.selectElevatorEffectedListByDate(startDate, endDate);
		if (ObjectUtil.isNotEmpty(elevatorEffectedList)) {
			Map<String, List<ElevatorEffectedVO>> dateGroup;
			if (dateType.equals(1)) {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M/d")));
			} else if (dateType.equals(2)) {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getRecordDate()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getRecordDate()), "yyyy/M/d"))));
			} else {
				dateGroup = elevatorEffectedList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getRecordDate(), "yyyy/M")));
			}
			initList.forEach(e -> dateGroup.forEach((k, v) -> {
				if (e.get("日期").equals(k)){
					e.put("监控梯台数",String.valueOf(v.stream().map(ElevatorEffectedVO::getElevatorId).distinct().count()));
				}
			}));
		}
		if (ObjectUtil.isNotEmpty(planList)) {
			Map<String, List<BiWxPlanListDTO>> dateGroup;
			if (dateType.equals(1)) {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M/d")));
			} else if (dateType.equals(2)) {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> String.format("%s~%s", DateUtil.format(DateUtil.beginOfWeek(t.getPlanCreateTime()), "yyyy/M/d"), DateUtil.format(DateUtil.endOfWeek(t.getPlanCreateTime()), "yyyy/M/d"))));
			} else {
				dateGroup = planList.stream().collect(Collectors.groupingBy(t -> DateUtil.format(t.getPlanCreateTime(), "yyyy/M")));
			}
			initList.forEach(e -> dateGroup.forEach((k, v) -> {
				if (e.get("日期").equals(k)){
					e.put("报障工单数",String.valueOf(v.stream().map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("报障状态为停梯的工单数",String.valueOf(v.stream().filter(t -> t.getPlanElevatorStop().equals(2)).map(BiWxPlanListDTO::getPlanId).distinct().count()));
					e.put("报障状态为停梯的电梯数",String.valueOf(v.stream().filter(t -> t.getPlanElevatorStop().equals(2)).map(BiWxPlanListDTO::getElevatorId).distinct().count()));
				}
			}));
		}
		initList.forEach(e -> {
			List<String> row = new ArrayList<>();
			row.add(e.get("日期"));
			row.add(e.get("监控梯台数"));
			row.add(e.get("报障工单数"));
			row.add(e.get("报障状态为停梯的工单数"));
			row.add(e.get("报障状态为停梯的电梯数"));
			rows.add(row);
		});
	}

}
